#include <benchmark/benchmark.h>
#include "unistd.h"
#include "stddef.h"
#include "fenv.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "util.h"

using namespace std;

// 取得当前进程的识别码
static void Bm_function_Getpid(benchmark::State &state)
{
    pid_t pid;
    for (auto _ : state)
    {
        pid = getpid();
        benchmark::DoNotOptimize(pid);
    }
    state.SetBytesProcessed(state.iterations());
}

static void Bm_function_Geteuid(benchmark::State &state)
{
    uid_t uid;
    for (auto _ : state)
    {
        uid = geteuid();
        benchmark::DoNotOptimize(uid);
    }
    state.SetBytesProcessed(state.iterations());
}

static void Bm_function_Close(benchmark::State &state)
{
    for (auto _ : state)
    {
        int fd = open("/data/testClose.txt", O_RDONLY | O_CREAT);
        if (fd > 0)
        {
            benchmark::DoNotOptimize(close(fd));
        }
    }
    state.SetBytesProcessed(state.iterations());
}

// static void Bm_function_Usleep(benchmark::State &state)
// {
//     int sleep_time = 100;
//     for (auto _ : state)
//     {
//         benchmark::DoNotOptimize(usleep(sleep_time));
//     }
//     state.SetBytesProcessed(state.iterations());
// }

static void Bm_function_Pwrite64(benchmark::State &state)
{
    const char *buf = "Hello, world!";
    off64_t offset = 0;
    ssize_t nwritten;
    int fd = open("test.txt", O_WRONLY, S_IRUSR | S_IWUSR);
    if (fd == -1)
    {
        perror("open pwrite64");
        exit(EXIT_FAILURE);
    }
    for (auto _ : state)
    {
        nwritten = pwrite64(fd, buf, strlen(buf), offset);
        if (nwritten == -1)
        {
            perror("pwrite64");
            exit(EXIT_FAILURE);
        }
        benchmark::DoNotOptimize(nwritten);
    }

    close(fd);
    state.SetBytesProcessed(state.iterations());
}

static void Bm_function_Pread64(benchmark::State &state)
{
    char buf[1024];
    int fd;
    off64_t offset = 0;
    ssize_t nread;
    fd = open("test.txt", O_RDONLY);
    if (fd == -1)
    {
        perror("open pread64");
        exit(EXIT_FAILURE);
    }
    for (auto _ : state)
    {
        nread = pread64(fd, buf, sizeof(buf), offset);
        if (nread == -1)
        {
            perror("pread64");
            exit(EXIT_FAILURE);
        }
        benchmark::DoNotOptimize(nread);
    }
    close(fd);
    state.SetBytesProcessed(state.iterations());
}

static void Bm_function_Readlink(benchmark::State &state)
{
    char path[1024];
    ssize_t len;
    for (auto _ : state)
    {
        len = readlink("/system/app", path, sizeof(path) - 1);
        benchmark::DoNotOptimize(len);
    }
    state.SetBytesProcessed(state.iterations());
}

static void Bm_function_Getuid(benchmark::State &state)
{
    uid_t uid;
    for (auto _ : state)
    {
        uid = getuid();
        benchmark::DoNotOptimize(uid);
    }
    state.SetItemsProcessed(state.iterations());
}

static void Bm_function_Getegid(benchmark::State &state)
{
    gid_t gid;
    for (auto _ : state)
    {
        gid = getegid();
        benchmark::DoNotOptimize(gid);
    }
    state.SetItemsProcessed(state.iterations());
}

static void Bm_function_Read(benchmark::State &state)
{
    int fd = open("/etc/passwd", O_RDONLY);
    if (fd == -1)
    {
        perror("open read");
        exit(EXIT_FAILURE);
    }
    char *readBuf = (char *)malloc(16);
    if (readBuf == nullptr)
    {
        perror("malloc read");
        exit(EXIT_FAILURE);
    }
    for (auto _ : state)
    {
        benchmark::DoNotOptimize(read(fd, readBuf, 15));
    }
    if (readBuf != nullptr)
    {
        free(readBuf);
    }
    close(fd);
    state.SetItemsProcessed(state.iterations());
}

static void Bm_function_Write(benchmark::State &state)
{
    const char *buf = "hello world!";
    int fd = open("/data/data/tmp.txt", O_RDWR | O_CREAT, 0655);
    if (fd == -1)
    {
        perror("open write");
        exit(EXIT_FAILURE);
    }

    for (auto _ : state)
    {
        benchmark::DoNotOptimize(write(fd, buf, strlen(buf)));
    }
    close(fd);
    state.SetItemsProcessed(state.iterations());
}

static void Bm_function_Access(benchmark::State &state)
{
    for (auto _ : state)
    {
		const char* filename = "/data";
        benchmark::DoNotOptimize(access(filename , F_OK));
    }
    state.SetBytesProcessed(state.iterations());
}

MUSL_BENCHMARK(Bm_function_Getpid);
MUSL_BENCHMARK(Bm_function_Geteuid);
MUSL_BENCHMARK(Bm_function_Pwrite64);
MUSL_BENCHMARK(Bm_function_Readlink);
MUSL_BENCHMARK(Bm_function_Pread64);
MUSL_BENCHMARK(Bm_function_Close);
/* MUSL_BENCHMARK(Bm_function_Usleep); */
MUSL_BENCHMARK(Bm_function_Getuid);
MUSL_BENCHMARK(Bm_function_Getegid);
MUSL_BENCHMARK(Bm_function_Read);
MUSL_BENCHMARK(Bm_function_Write);
MUSL_BENCHMARK(Bm_function_Access);